package com.yang.sofa;

//import com.alipay.sofa.boot.annotation.PlaceHolderBinder;
//import com.alipay.sofa.boot.annotation.PlaceHolderAnnotationInvocationHandler.AnnotationWrapperBuilder;
//import com.alipay.sofa.boot.error.ErrorCode;
//import com.alipay.sofa.boot.util.BeanDefinitionUtil;
//import com.alipay.sofa.runtime.api.annotation.SofaAsyncInit;
//
//import com.alipay.sofa.runtime.factory.BeanLoadCostBeanFactory;
//import com.alipay.sofa.runtime.log.SofaLogger;
//import com.alipay.sofa.runtime.spring.async.AsyncInitBeanHolder;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.Environment;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.util.ClassUtils;

public class AsyncInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor, ApplicationContextAware, EnvironmentAware {
    private final PlaceHolderBinder binder = new AsyncInitBeanFactoryPostProcessor.DefaultPlaceHolderBinder();
    private Environment environment;
    private String moduleName;

    public AsyncInitBeanFactoryPostProcessor() {
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Stream var10000 = Arrays.stream(beanFactory.getBeanDefinitionNames());
        Function var10001 = Function.identity();
        beanFactory.getClass();
        ((Map)var10000.collect(Collectors.toMap(var10001, beanFactory::getBeanDefinition))).forEach((key, value) -> {
            this.scanAsyncInitBeanDefinition(key, value, beanFactory);
        });
    }

    private void scanAsyncInitBeanDefinition(String beanId, BeanDefinition beanDefinition, ConfigurableListableBeanFactory beanFactory) {
        if (BeanDefinitionUtil.isFromConfigurationSource(beanDefinition)) {
            this.scanAsyncInitBeanDefinitionOnMethod(beanId, (AnnotatedBeanDefinition)beanDefinition);
        } else {
            Class<?> beanClassType = BeanDefinitionUtil.resolveBeanClassType(beanDefinition);
            if (beanClassType == null) {
                SofaLogger.warn("Bean class type cant be resolved from bean of {}", beanId);
                return;
            }

            this.scanAsyncInitBeanDefinitionOnClass(beanId, beanClassType, beanDefinition, beanFactory);
        }

    }

    private void scanAsyncInitBeanDefinitionOnMethod(String beanId, AnnotatedBeanDefinition beanDefinition) {
        List<Method> candidateMethods = new ArrayList();
        MethodMetadata methodMetadata = beanDefinition.getFactoryMethodMetadata();

        Class returnType;
        Class declaringClass;
        try {
            returnType = ClassUtils.forName(methodMetadata.getReturnTypeName(), (ClassLoader)null);
            declaringClass = ClassUtils.forName(methodMetadata.getDeclaringClassName(), (ClassLoader)null);
        } catch (Throwable var13) {
            SofaLogger.error(ErrorCode.convert("01-02001", new Object[]{beanId}), var13);
            return;
        }

        if (methodMetadata instanceof StandardMethodMetadata) {
            candidateMethods.add(((StandardMethodMetadata)methodMetadata).getIntrospectedMethod());
        } else {
            Method[] var7 = declaringClass.getDeclaredMethods();
            int var8 = var7.length;

            for(int var9 = 0; var9 < var8; ++var9) {
                Method m = var7[var9];
                if (m.getName().equals(methodMetadata.getMethodName()) && m.getReturnType().getTypeName().equals(methodMetadata.getReturnTypeName()) && AnnotatedElementUtils.hasAnnotation(m, Bean.class)) {
                    Bean bean = (Bean)m.getAnnotation(Bean.class);
                    Set<String> beanNames = new HashSet();
                    beanNames.add(m.getName());
                    if (bean != null) {
                        beanNames.addAll(Arrays.asList(bean.name()));
                        beanNames.addAll(Arrays.asList(bean.value()));
                    }

                    if (beanNames.contains(beanId)) {
                        candidateMethods.add(m);
                    }
                }
            }
        }

        if (candidateMethods.size() == 1) {
            SofaAsyncInit sofaAsyncInitAnnotation = (SofaAsyncInit)((Method)candidateMethods.get(0)).getAnnotation(SofaAsyncInit.class);
            if (sofaAsyncInitAnnotation == null) {
                sofaAsyncInitAnnotation = (SofaAsyncInit)returnType.getAnnotation(SofaAsyncInit.class);
            }

            this.registerAsyncInitBean(beanId, sofaAsyncInitAnnotation, beanDefinition);
        } else if (candidateMethods.size() > 1) {
            Iterator var14 = candidateMethods.iterator();

            while(var14.hasNext()) {
                Method m = (Method)var14.next();
                if (AnnotatedElementUtils.hasAnnotation(m, SofaAsyncInit.class) || AnnotatedElementUtils.hasAnnotation(returnType, SofaAsyncInit.class)) {
                    throw new FatalBeanException(ErrorCode.convert("01-02002", new Object[]{declaringClass.getCanonicalName()}));
                }
            }
        }

    }

    private void scanAsyncInitBeanDefinitionOnClass(String beanId, Class<?> beanClass, BeanDefinition beanDefinition, ConfigurableListableBeanFactory beanFactory) {
        SofaAsyncInit sofaAsyncInitAnnotation = (SofaAsyncInit)AnnotationUtils.findAnnotation(beanClass, SofaAsyncInit.class);
        this.registerAsyncInitBean(beanId, sofaAsyncInitAnnotation, beanDefinition);
    }

    private void registerAsyncInitBean(String beanId, SofaAsyncInit sofaAsyncInitAnnotation, BeanDefinition beanDefinition) {
        if (sofaAsyncInitAnnotation != null) {
            PlaceHolderAnnotationInvocationHandler.AnnotationWrapperBuilder wrapperBuilder = PlaceHolderAnnotationInvocationHandler.AnnotationWrapperBuilder.wrap(sofaAsyncInitAnnotation).withBinder(this.binder);

            sofaAsyncInitAnnotation = (SofaAsyncInit)wrapperBuilder.build();
            if (sofaAsyncInitAnnotation.value()) {
                AsyncInitBeanHolder.registerAsyncInitBean(this.moduleName, beanId, beanDefinition.getInitMethodName());
            }

        }
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.moduleName = this.getModuleName(applicationContext);
    }

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    private String getModuleName(ApplicationContext applicationContext) {
        BeanFactory beanFactory = ((AbstractApplicationContext)applicationContext).getBeanFactory();
        return beanFactory instanceof BeanLoadCostBeanFactory ? ((BeanLoadCostBeanFactory)beanFactory).getId() : "RootApplicationContext";
    }

    class DefaultPlaceHolderBinder implements PlaceHolderBinder {
        DefaultPlaceHolderBinder() {
        }

        public String bind(String text) {
            return AsyncInitBeanFactoryPostProcessor.this.environment.resolvePlaceholders(text);
        }
    }
}
